package BusinessLogic;

import DataLayer.Database;
import Presentation.frmServer;
import java.net.*;
import java.io.*;
import java.nio.charset.Charset;

public class ServerServices implements Cloneable, Runnable{
    
    static frmServer myFrame;
    boolean Stop=false;
    ServerSocket Server=null;
    Socket Data=null;
    Thread Runner=null;
    BufferedWriter bw=null;
    BufferedReader br=null;
    private String name="client";
    private String pass="";
    Database db=new Database();
    private int State=0;
    
    public ServerServices(){
   
    }
    
    public synchronized void startServer(frmServer frm, int port) throws IOException{
        if(Runner==null){
            Server=new ServerSocket(port);
            Runner=new Thread(this);
            Runner.start();
            myFrame=frm;
         }
    }
    
    // Dừng server
    public synchronized void stopServer(){
        if(Server!=null){
            db.closedServer();
            Stop=true;
            Runner=null;
            try{
                Server.close();
                myFrame.addLog("Server đã tắt");
            }
            catch(Exception e){
                myFrame.addLog("Lỗi khi tắt server\n"+e.toString());
            }
        }
        else{
            db.closedServer();
            myFrame.addLog("Lỗi khi tắt server");
        }
    }
    
    //chay Server de lang nghe cac yeu cau tu client
    public void run(){
       if(Server!=null){
           while(!Stop){
               try{
                    Socket dsocket=Server.accept();
                    ServerServices newsocket=(ServerServices)clone();
                    newsocket.Server=null;
                    newsocket.Data=dsocket;
                    newsocket.Runner=new Thread(newsocket);
                    newsocket.Runner.start();//chay server
               }
               catch(Exception e){
                  
               }
           }
       }
       else{
           if(Data!=null){
               try{
                    run(Data);
               }
                catch(Exception e) {
                    myFrame.addLog("2"+e.toString());}
           }
       }
    }
    
    public void run(Socket s) {
        try{
            br=new BufferedReader(new InputStreamReader(s.getInputStream(),Charset.forName("UTF-8").newDecoder()));
            bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream(),Charset.forName("UTF-8").newEncoder()));
            while (!Stop) {
                String str = br.readLine();
                if (str == null) {
                    Stop = true;
                } else {
                    processingData(str);    //Xử lý dữ liệu được gửi lên server
                }
            }
            //Nếu client đăng xuất
            State=db.status(name);
            if(State!=0 && State!=3){
                String ds=db.getListFriendOnline(name);
                    int spos=0,epos=-1;
                    String friendname;
                    for(int j=0;j<ds.length();j++){
                        if(ds.charAt(j)==001){
                            spos=epos+1;
                            epos=j;
                            friendname=new String(ds.substring(spos,epos)); 
                            String send=Command.FRIEND_STATE+Command.OFFLINE+friendname+((char)001)+name;
                            myFrame.sendToSelected(friendname, send);
                         }
                    }
            }
            String gr=db.findGroup(name);   
            String[] arrU = db.getMemberInGroup(gr);
                for (String member : arrU) {
                    if(!member.equals(name))myFrame.sendToSelected(member, Command.REMOVE_MEMBER_GROUP+name);
            }
            db.removeFromGroup(name);
            myFrame.removeClient(this);
            db.logout(name);
            Data.close();
        }
        catch(IOException e){
            myFrame.addLog(name+ " đã ngắt kết nối");
            myFrame.removeClient(this);
            db.logout(name);
        }
    }
    
    //Server gửi dữ liệu đến client
    public void sendData(String str)
    {
        try{
             bw.write(str);
             bw.newLine();
             bw.flush();
        }
        catch(IOException e){
            myFrame.addLog(e.toString());
        }
    }
    
    @Override
    public String toString()
    {
        if(Data!=null){
            return (name+"@"+Data.getRemoteSocketAddress().toString().substring(1));
        }
        else{
            return ("Lỗi! Không thể phân tích");
        }
    }
    
    //lấy trạng thái của user
    public int state_User(String username){
        return Database.status(username);
    }
    
     //Xử lý dữ liệu được gửi tới
    private void processingData(String str){
        String friend ="", State=null;
        String send="";
        String command=new String(str.substring(0,3));
        int sep=str.indexOf(((char)001));
        int sep1=str.indexOf(((char)002));
        int intCommand=Integer.parseInt(command);
        switch (intCommand)
        {
            //Kiểm tra yêu cầu đăng nhập từ client
            // <editor-fold defaultstate="collapsed" desc="LOGIN_REQUEST">
            case(Command.LOGIN_REQUEST):      
                State = str.substring(3,4);
                name = str.substring(4,sep);
                pass = str.substring(sep+1,str.length());
                int spos=0,epos=-1;
                if(db.login(name, pass)){
                    myFrame.addClient(this);
                    sendData(Command.LOGIN_SUCCESS+State+name+((char)001)+db.getFriendList(name)+((char)002)+db.getFriendIsLock(name));       //Cho phép đăng nhập
                    myFrame.addLog(name+" đã đăng nhập");
                }
                else{
                    sendData(Command.LOGIN_FAIL+name);       //Đăng nhập không đúng
                }
                //Kiểm tra danh sách yêu cầu kết bạn
                if (db.checkFriendRequest(name)) {
                    String listuser = db.getListUserRequest(name);
                    String sender;
                    spos = 0;
                    epos = -1;
                    for (int i = 0; i < listuser.length(); i++) {
                        if (listuser.charAt(i) == 001) {
                            spos = epos + 1;
                            epos = i;
                            sender = listuser.substring(spos, epos);
                            String st=String.valueOf(db.status(sender));
                            sendData(Command.ADD_FRIEND_REQUEST + st + name + ((char) 001) + sender);
                        }
                    }
                }     
                 //Kiểm tra tin nhắn offline
                    if(db.checkOfflineMessage(name)){
                        String dsuser = db.getListUserSendMessageOffline(name);
                        String senders;
                        spos=0;epos=-1;
                        for(int i=0;i<dsuser.length();i++){
                            if(dsuser.charAt(i)==001){
                                spos=epos+1;
                                epos=i;
                                senders=dsuser.substring(spos,epos);
                                int count=db.loopCountOffMessageOffline(senders,name);
                                sendData(Command.CHAT_OPEN+name+((char)001)+senders+((char)002)+count);
                                for(int j=0;j<count;j++){
                                    sendData(Command.MESSAGE_OFFLINE+db.getMessageOffline(senders, name)[j]);  
                                } 
                            }
                       }
                   }
                break;
            // </editor-fold>
                
            //Gửi trạng thái
            // <editor-fold defaultstate="collapsed" desc="SEND_STATE">
            case(Command.SEND_STATE):
                State = str.substring(3,4);
                name = str.substring(4,str.length());
                db.setStatus(name, State);
                if(State.equals(Command.INVISIBLE)) State=Command.OFFLINE;
                String ds=db.getListFriendOnline(name);
                spos=0;
                epos=-1;
                String friendname;
                for(int j=0;j<ds.length();j++){
                    if(ds.charAt(j)==001){
                        spos=epos+1;
                        epos=j;
                        friendname=new String(ds.substring(spos,epos));
                        send=Command.FRIEND_STATE+State+friendname+((char)001)+name;
                        myFrame.sendToSelected(friendname, send);
                     }
                }
                
                break;
            // </editor-fold>
                
            //Xóa tin nhắn offline khi người dùng đã xem tin nhắn đó  
            // <editor-fold defaultstate="collapsed" desc="IS_WATCHED_MESSAGE_OFFLINE">
            case(Command.IS_WATCHED_MESSAGE_OFFLINE):
               name=str.substring(3,sep);
               friend=str.substring(sep+1,str.length());
               if(db.deleteMessageOffline(friend, name)){
                   myFrame.addLog("Đã xóa tin nhắn offline của "+name);
               }
               else{
                   myFrame.addLog("Lỗi! Không xóa được tin nhắn offline của "+name);
               }
               break;
                // </editor-fold>
                
            //Kểm tra yêu cầu đăng ký từ client
            // <editor-fold defaultstate="collapsed" desc="REGISTER_REQUEST">
            case(Command.REGISTER_REQUEST):      
                name=str.substring(3,sep);
                pass=str.substring(sep+1,str.length());
                if(db.addUser(name, pass)){
                    myFrame.addLog(name+" đã đăng ký thành công ");
                    sendData(Command.REGISTER_SUCCESS+name);       //Đăng ký thành công
                }
                else{
                    sendData(Command.REGISTER_FAIL+name);       //Không đăng kí được
                }
                break;
            // </editor-fold>
             
            //Kiểm tra yêu cầu thêm bạn
            // <editor-fold defaultstate="collapsed" desc="ADD_FRIEND_REQUEST">   
            case (Command.ADD_FRIEND_REQUEST):
                name = str.substring(3, sep);
                friend = str.substring(sep + 1, str.length());
                State = String.valueOf(db.status(name));
                if(State.equals(Command.INVISIBLE)) State=Command.OFFLINE;
                if (db.existUser(friend) && !name.equals(friend)) {
                    if (!db.isFriend(name, friend)) {
                        if (db.status(friend) != Integer.parseInt(Command.OFFLINE)) {
                            myFrame.sendToSelected(friend, Command.ADD_FRIEND_REQUEST+State+ friend + ((char) 001) + name);   //Thêm bạn thành công
                        } else {
                            db.saveFriendRequest(name, friend);
                            sendData(Command.ADD_FRIEND_WAIT+friend);
                        }
                        myFrame.addLog(name+" đã gửi yêu cầu kết bạn đến "+friend);
                    } else {
                        sendData(Command.ADD_ALREADY_FRIEND + friend);    //Đã là bạn
                    }
                } else {
                    sendData(Command.ADD_NO_EXIST + friend);        //Không tồn tại
                }
                break;
            // </editor-fold>
            
            //Xử lý đồng ý kết bạn    
            // <editor-fold defaultstate="collapsed" desc="ADD_FRIEND_ACCEPT">
            case(Command.ADD_FRIEND_ACCEPT):
                name=str.substring(3,sep);
                friend=str.substring(sep+1,str.length());
                State = String.valueOf(db.status(name));
                if(State.equals(Command.INVISIBLE)) State=Command.OFFLINE;
                db.addFriends(name, friend);
                db.addFriends(friend, name);
                db.deleteFriendRequest(friend, name);
                myFrame.addLog(name+" và "+friend+" đã trở thành bạn");
                myFrame.sendToSelected(friend, Command.ADD_FRIEND_SUCCESS+State+name);
                break;
            // </editor-fold>
               
            //Từ chối kết bạn
            // <editor-fold defaultstate="collapsed" desc="ADD_FRIEND_REFUSE">
            case(Command.ADD_FRIEND_REFUSE):
                name=str.substring(3,sep);
                friend=str.substring(sep+1,str.length());
                db.deleteFriendRequest(friend, name);
                myFrame.addLog(name+" đã từ chối kết bạn với" + friend);
                myFrame.sendToSelected(friend, Command.ADD_FRIEND_FAIL+name);
                break;
            // </editor-fold>
                
            //Yêu cầu chat
            // <editor-fold defaultstate="collapsed" desc="CHAT_FRIEND_REQUEST">    
            case(Command.CHAT_FRIEND_REQUEST):      //Kiểm tra yêu cầu chat
                name = str.substring(3,sep);
                friend = str.substring(sep+1,str.length());
                if(db.isFriend(name,friend)){
                    sendData(Command.CHAT_REQUEST_SUCCESS+name+((char)001)+friend);         //Mở khung chat
                }
                else sendData(Command.CHAT_REQUEST_FAIL+friend);        //Không thể chat
                break;
            // </editor-fold>
            
            //Yêu cầu đổi mật khẩu    
            // <editor-fold defaultstate="collapsed" desc="CHANGE_PASS_REQUEST">    
            case(Command.CHANGE_PASS_REQUEST):
                name = str.substring(3,sep);
                String newpass=str.substring(sep+1, str.length());                             
                try{
                    db.changePass(name, newpass);
                    sendData(Command.CHANGE_PASS_SUCCESS+name);                       //thay đổi thành công    
                    myFrame.addLog(name+" vừa thay đổi mật khẩu");
                }
                catch(Exception e){
                    sendData(Command.CHANGE_PASS_FAIL+name);                       // thay đổi thất bại
                }
                break;
             // </editor-fold>
                
            //Yêu cầu khóa người dùng
            // <editor-fold defaultstate="collapsed" desc="LOCK_FRIEND_REQUEST">  
            case(Command.LOCK_FRIEND_REQUEST):         
                name = str.substring(3,sep);
                friend=str.substring(sep+1, str.length());  
                try{
                    if(db.isFriend(name, friend)){                       
                        if(db.checkLocked(name, friend)){
                            sendData(Command.LOCK_ALREADY+name+((char)001)+friend);     // người này đã bị khóa rồi
                        }
                        else{
                            db.lockFriend(name, friend);
                            sendData(Command.LOCK_SUCCESS+name+((char)001)+friend);      // khóa thành công
                            myFrame.addLog(name+" đã khóa "+friend);
                        }
                   }
                    else{
                        sendData(Command.LOCK_NOT_FRIEND+name+((char)001)+friend);  // user này ko phải là bạn
                    }
                }
                catch(Exception e){
                    sendData(Command.LOCK_FAIL+name);   // yêu cầu khóa người dùng thất bại
                }
                break;
            // </editor-fold>
                
            //Yêu cầu mở khóa người dùng    
            // <editor-fold defaultstate="collapsed" desc="UNLOCK_FRIEND_REQUEST">       
            case(Command.UNLOCK_FRIEND_REQUEST):      
                name = str.substring(3,sep);
                String nameunlock=str.substring(sep+1, str.length());  
                try{
                    if(db.isFriend(name, nameunlock)){                       
                        if(db.checkLocked(name, nameunlock)){
                            db.UnlockFriend(name, nameunlock);
                            sendData(Command.UNLOCK_SUCCESS+name+((char)001)+nameunlock);     // mở khóa thành công
                            myFrame.addLog(name+" đã mở khóa "+nameunlock);
                        }
                        else{
                            sendData(Command.UNLOCK_NOT_LOCK+name+((char)001)+nameunlock);      // người dùng này không có bị khóa
                        }
                   }
                    else{
                        sendData(Command.UNLOCK_NOT_FRIEND+name+((char)001)+nameunlock);  // user này ko phải là bạn
                    }
                }
                catch(Exception e){
                    sendData(Command.UNLOCK_FAIL+name);   // yêu cầu mở khóa người dùng thất bại
                }
                break;
                // </editor-fold>
            
            //Yêu cầu xóa bạn    
            //<editor-fold defaultstate="collapsed" desc="DELETE_FRIEND_REQUEST">
            case(Command.DELETE_FRIEND_REQUEST):
                name=str.substring(3, sep);
                friend=str.substring(sep+1, str.length());
                try{
                    db.deleteFriend(name, friend);
                    db.deleteFriend(friend, name);
                    db.deleteMessageOffline(name, friend); // xóa tin nhắn offline sau khi xóa bạn
                    sendData(Command.DELETE_SUCCESS+name+((char)001)+friend);
                    if(db.status(friend)!=0){
                        myFrame.sendToSelected(friend, Command.IS_DELETE+name);
                    }
                    myFrame.addLog(name+" và "+friend+" đã xóa bạn");
                }
                catch(Exception e){
                    sendData(Command.DELETE_FAIL+friend);
                }
                break;
            //</editor-fold>
                
            //Tìm bạn    
            // <editor-fold defaultstate="collapsed" desc="FIND_FRIEND">  
            case(Command.FIND_FRIEND):
                String namefind=str.substring(3, str.length());
                try{
                    sendData(Command.FIND_LIST+db.findFriend(namefind));    //tra ve danh sach user giong voi userfind
                }
                catch(Exception e)
                {
                    sendData(Command.FIND_FAIL+namefind);   // loi tim kiem ban
                }
                break;
            // </editor-fold>    
                
            //Kiểm tra nội dung chat    
            // <editor-fold defaultstate="collapsed" desc="MESSAGE_SEND">      
            case(Command.MESSAGE_SEND):      
                String style=str.substring(3,10);
                name = str.substring(10,sep);
                friend = str.substring(sep+1,sep1);
                String msg = str.substring(sep1+1,str.length());
                if(!db.checkLocked(friend, name)){
                    if(db.status(friend)!=0){
                        send = Command.SEND_TO_FRIEND+style+friend+((char)001)+name+((char)002)+msg;
                        myFrame.sendToSelected(friend, send);
                    }
                    else{
                        db.messageOffline(name, friend, msg);
                    }
                }
                break;
           // </editor-fold>     
                
            //Buzz    
            // <editor-fold defaultstate="collapsed" desc="BUZZ">      
            case(Command.BUZZ):      
                name = str.substring(3,sep);
                friend = str.substring(sep+1,str.length());
                String buzz = Command.SEND_BUZZ+friend+((char)001)+name;
                myFrame.sendToSelected(friend, buzz);
                break;
            // </editor-fold>
                
            //Tạo nhóm chat
            // <editor-fold defaultstate="collapsed" desc="CREATE_GROUP"> 
            case (Command.CREATE_GROUP):
                name = str.substring(3, sep);
                String group = str.substring(sep + 1, str.length());
                myFrame.addLog(name + ": gửi yêu cầu tạo nhóm mới");
                //kiểm tra có tồn tại group hay không?
                if (db.checkJoinGroup(name)) {
                    sendData(Command.ALREADY_JOIN_GROUP + name);
                } else {
                    if (db.existsGroup(group) || db.checkCreateGroup(name)) {
                        myFrame.addLog(name + ": đã tồn tại nhóm");
                        sendData(Command.EXISTS_GROUP + name + ((char) 001) + group);
                    } else {
                        try {
                            db.createGroup(group, name);
                            myFrame.addLog(name + ": tạo nhóm mới thành công");
                            db.addMember(name, group);
                            sendData(Command.CREATE_GROUP_SUCCESS + name + ((char) 001) + group);
                        } catch (Exception e) {
                            myFrame.addLog(name + ": tạo nhóm thất bại");
                            sendData(Command.CREATE_GROUP_FAIL + name);
                        }
                    }
                }
                break;
            // </editor-fold>
                
            //mời tham gia nhóm chat
            // <editor-fold defaultstate="collapsed" desc="JOIN_GROUP_REQUEST">
            case (Command.JOIN_GROUP_REQUEST):
                name = str.substring(3, sep);
                friend = str.substring(sep + 1, sep1);
                group = str.substring(sep1 + 1, str.length());
                if(!db.checkJoinGroup(friend)){
                    send = Command.HAVE_REQUEST_JOIN_GROUP + friend + ((char) 001) + name + ((char) 002) + group;
                    myFrame.sendToSelected(friend, send);
                }
                break;
            // </editor-fold>
                
            //chấp nhận gia nhập nhóm
            // <editor-fold defaultstate="collapsed" desc="JOIN_GROUP_ACCEPT">
            case (Command.JOIN_GROUP_ACCEPT):
                name = str.substring(3, sep);
                friend = str.substring(sep + 1, sep1);
                group = str.substring(sep1 + 1, str.length());
                db.addMember(name, group);
                String[] arrUser;
                arrUser = db.getMemberInGroup(group);
                for (String member : arrUser) {
                    send = Command.GROUP_ADD_NEW_USER + name + ((char) 001) + member + ((char) 002) + group;
                    sendData(send);
                    if(!member.equals(name))myFrame.sendToSelected(member, Command.ADD_NEW_MEMBER + member + ((char) 001) + name + ((char) 002) + group);
                }
                break;
            // </editor-fold>
                
             //gửi tin nhắn đến nhóm chat
            // <editor-fold defaultstate="collapsed" desc="MESSAGE_SEND_GROUP">
            case (Command.MESSAGE_SEND_GROUP):
                style=str.substring(3,10);
                name = str.substring(10,sep);
                group = str.substring(sep+1,sep1);
                String gmsg = str.substring(sep1+1,str.length());
                arrUser = db.getMemberInGroup(group);
                for (String member : arrUser) {
                    if(!member.equals(name))myFrame.sendToSelected(member, Command.MESSAGE_RECIEVED_GROUP+style+((char)001)+name+((char)002)+gmsg);
                }
                break;
            // </editor-fold>
                
            //Yêu cầu xóa nhóm
            // <editor-fold defaultstate="collapsed" desc="REMOVE_GROUP">
            case (Command.REMOVE_GROUP):
                name = str.substring(3, str.length());
                group = db.findGroupCreate(name);
                if (!group.equals(((char)001)+"")) {
                    try {
                        arrUser = db.getMemberInGroup(group);
                        for (String member : arrUser) {
                            if (!member.equals(name)) {
                                myFrame.sendToSelected(member, Command.REMOVE_GROUP + name);
                            }
                        }
                    } finally {
                        db.removeGroup(name, group);
                        if(db.isJoinGroup(name))
                            sendData(Command.REMOVE_GROUP_SUCCESS + name);
                        else sendData(Command.REMOVE_GROUP_SUCCESS_AND_CLOSE + name);
                    }
                }
                break;
            // </editor-fold>
                
            //Xóa khi thoát khỏi nhóm chat
            // <editor-fold defaultstate="collapsed" desc="LEAVE_GROUP">
            case (Command.LEAVE_GROUP):
                name = str.substring(3,sep);
                group = str.substring(sep+1,str.length());
                db.removeMember(name, group);
                arrUser = db.getMemberInGroup(group);
                for (String member : arrUser) {
                    if(!member.equals(name))myFrame.sendToSelected(member, Command.REMOVE_MEMBER_GROUP+name);
                }
                break;
            // </editor-fold>
                
            default:
                break;
        }
    }
}
